import type { Ref, WritableComputedRef } from "vue";
import type { FormInstance, FormRules } from "element-plus";
import { ref, reactive, computed, watch, nextTick } from "vue";
import { sleep } from "@/utils/sleep";

// 深度拷贝
function deepClone<T>(obj: T): T {
  if (obj == null) return obj;
  return JSON.parse(JSON.stringify(obj));
}

type Options<T extends Record<string, any>, LP extends Array<any> = []> = {
  visibleRef?: Ref<boolean> | WritableComputedRef<boolean, boolean>;
  // Element Plus Form
  elFormRef?: Ref<FormInstance>;
  // 标题
  title?: string;
  // 默认数据
  defaultForm?: T;
  // 校验规则
  rules?: Partial<Record<keyof T, Record<string, any> | Record<string, any>[]>>;
  // rules?: FormRules<T>
  // 初始化数据
  loadData?: (
    ...args: LP extends [] ? [Partial<T> | undefined] : LP
  ) => Promise<(Partial<T> & Record<string, any>) | null | undefined | void>;
  // 提交数据
  handleSubmit?: (form: T) => void | Promise<void>;
  // 添加数据
  handleCreateSubmit?: (form: T) => void | Promise<void>;
  // 更新数据
  handleUpdateSubmit?: (form: T) => void | Promise<void>;
};

export function useGeneralDialogForm<
  T extends Record<string, any>,
  LP extends Array<any> = []
>(options?: Options<T, LP>) {
  // 显示
  const visible = options?.visibleRef ?? ref(false);

  // 加载的数据
  const data = ref<T | null>(null);

  // 加载状态
  const loading = ref(false);

  // 初始化数据
  const loadData = async (
    ...args: LP extends [] ? [Partial<T> | undefined] : LP
  ) => {
    loading.value = true;
    try {
      data.value = options?.loadData
        ? await Promise.resolve(options?.loadData(...args))
        : (args[0] ?? null);
      await handleReset();
      loading.value = false;
    } catch (error) {
      loading.value = false;
      throw error;
    }
  };

  // 是否创建模式
  const isCreateMode = ref(true);
  // 是否更新模式
  const isUpdateMode = ref(false);
  // 是否只读模式
  const isReadOnly = ref(false);

  // 标题
  const title = computed(
    () =>
      (isCreateMode.value ? "新增" : isReadOnly.value ? "查看" : "编辑") +
      (options?.title || "")
  );
  const originalTitle = computed(() => options?.title);

  // 表单
  const form = ref<T & { [key: string]: any }>(
    deepClone(options?.defaultForm || ({} as T))
  );

  // 校验规则
  const rules = computed<FormRules<T>>(() => options?.rules || {});

  // 校验
  const validate = async () => {
    await options?.elFormRef?.value?.validate();
  };

  const validateField = async (field: string) => {
    await options?.elFormRef?.value?.validateField(field);
  };

  // 清除校验
  const clearValidate = async () => {
    await sleep(0);
    options?.elFormRef?.value?.clearValidate();
    await nextTick();
  };

  // 重置
  const handleReset = async () => {
    form.value = Object.assign(
      deepClone(options?.defaultForm || ({} as T)),
      data.value
    );
    await clearValidate();
  };

  // 提交
  const submitLoading = ref(false);
  const handleSubmit = async (sendData?: Partial<T>) => {
    if (!visible.value) return;
    if (loading.value) return;
    if (submitLoading.value) return;
    submitLoading.value = true;
    try {
      await validate();

      const data = Object.assign(
        deepClone(options?.defaultForm || ({} as T)),
        form.value,
        sendData ?? {}
      );
      await options?.handleSubmit?.(data);
      if (isCreateMode.value) {
        await options?.handleCreateSubmit?.(data);
      } else {
        await options?.handleUpdateSubmit?.(data);
      }
      visible.value = false;
      submitLoading.value = false;
    } catch (error) {
      submitLoading.value = false;
      if (error === "cancel") return;
      console.error(error);
    }
  };

  // 打开添加弹窗
  const openCreateDialog = async (
    ...args: LP extends [] ? [] | [Partial<T>] : LP
  ) => {
    data.value = null;
    await handleReset();
    await loadData(...(args as any));
    isCreateMode.value = true;
    isUpdateMode.value = false;
    isReadOnly.value = false;
    visible.value = true;
    await clearValidate();
  };

  // 打开编辑弹窗
  const openUpdateDialog = async (
    ...args: LP extends [] ? [] | [Partial<T>] : LP
  ) => {
    data.value = null;
    await handleReset();
    await loadData(...(args as any));
    isCreateMode.value = false;
    isUpdateMode.value = true;
    isReadOnly.value = false;
    visible.value = true;
    await clearValidate();
  };

  // 打开查看弹窗
  const openViewDialog = async (
    ...args: LP extends [] ? [] | [Partial<T>] : LP
  ) => {
    data.value = null;
    await handleReset();
    await loadData(...(args as any));
    isCreateMode.value = false;
    isUpdateMode.value = false;
    isReadOnly.value = true;
    visible.value = true;
    await clearValidate();
  };

  // 关闭弹窗
  const closeDialog = async () => {
    visible.value = false;
  };

  watch(visible, async () => {
    if (!visible.value) {
      await handleReset();
    }
  });

  return reactive({
    visible,
    title,
    originalTitle,
    data,
    form,
    rules,
    isCreateMode,
    isUpdateMode,
    isReadOnly,
    loading,
    submitLoading,
    loadData,
    handleReset,
    handleSubmit,
    validate,
    validateField,
    clearValidate,
    openCreateDialog,
    openUpdateDialog,
    openViewDialog,
    closeDialog
  });
}
